home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / lang / mc302 / laptalk / laptalk.c < prev    next >
C/C++ Source or Header  |  1994-03-18  |  37KB  |  1,538 lines

  1. /*
  2.  * LAPTALK terminal program
  3.  *
  4.  * Copyright 1991-1994 Dave Dunfield
  5.  * All rights reserved.
  6.  *
  7.  * Permission granted for personal (non-commercial) use only.
  8.  *
  9.  * Compile with DDS MICRO-C compiler in 8086 TINY model.
  10.  *
  11.  * Compile command: cc laptalk -fop
  12.  */
  13. #include <stdio.h>
  14. #include <window.h>
  15. #include <comm.h>
  16. #include <file.h>
  17.  
  18. /* General definitions */
  19. #define    FSIZE            32        /* Max. size of a file name */
  20. #define    NFILES            8        /* Number of file entries */
  21. #define    FWIDTH            65        /* Width of file entries */
  22.  
  23. /* Script processor definitions */
  24. #define    NUM_VARS        26        /* Number of variables allowed */
  25. #define    CAPTURE_SIZE    256        /* Sizeof TX capture buffer */
  26.  
  27. /*
  28.  * Configuration parameters
  29.  * These MUST all be initialized in order to have default values,
  30.  * and to insure that they are of the same storage class.
  31.  */
  32. char homedir[FSIZE+1] = 0;            /* Default home directory */
  33. char filename[FSIZE+1] = { "*.*" };    /* Last filename accessed */
  34. char scriptfile[FSIZE+1]= { "*" };    /* Script file */
  35. int com_port = 0,                    /* Com port (1) */
  36.     baud = 5,                        /* Baud rate (9600) */
  37.     parity = 4,                        /* Parity (None) */
  38.     dbits = 3,                        /* Data bits (8) */
  39.     sbits = 0,                        /* Stop bits (1) */
  40.     flow = 1;                        /* Flow control (Enabled) */
  41. int    hangup_delay = 3,                /* Delay to hangup modem */
  42.     key_string_delay = 0,            /* Delay between chars in TX'd strings */
  43.     upl_char_delay = 0,                /* Delay between characters on upload */
  44.     upl_line_delay = 0,                /* Delay between lines on upload */
  45.     upl_sync_char = 0;                /* Upload synchronize character */
  46. int    tab_size = 8;                    /* Spacing of tab stops */
  47. char alarm = 0,                        /* Sound alarm on errors */
  48.     echotty = 0,                    /* Echo data sent in tty */
  49.     echosnd = 0,                    /* Echo data sent in scripts */
  50.     sendlf = 0,                        /* Line-feed in ASCII upload */
  51.     sendnull = 0,                    /* Send space on null lines */
  52.     hangmdm = 0;                    /* Hangup modem on exit */
  53. int attrs[] = {                        /* Window attributes */
  54.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 0: Main TTY screen */
  55.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 1: Attribute */
  56.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 2: Attribute */
  57.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 3: Attribute */
  58.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 4: Attribute */
  59.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 5: Attribute */
  60.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x07,    /* 6: Attribute */
  61.     WSAVE|WCOPEN|WLF|WSCROLL|WWRAP|0x70,    /* 7: Attribute */
  62.     WSAVE|WCOPEN|0x70,                        /* 8: Status line */
  63.     WSAVE|WCOPEN|WBOX2|0x70,                /* 9: Error Messages */
  64.     WSAVE|WCOPEN|WBOX3|0x70,                /* 10: String prompts */
  65.     WSAVE|WCOPEN|WBOX1|0x70,                /* 11: Setup screen 1 */
  66.     WCOPEN|WBOX2|0x70 };                    /* 12: Setup screen 2 */
  67. char protocols[NFILES][FWIDTH] = { "ASCII \\F\\A" };
  68. char scripts[NFILES][FWIDTH] = { 0 };
  69.  
  70. /* Window attribute identifiers */
  71. #define    TTY        0
  72. #define    STATUS    8
  73. #define    ERROR    9
  74. #define    STRING    10
  75. #define    SETUP1    11
  76. #define    SETUP2    12
  77.  
  78. /*
  79.  * ANSI (VT100) Function key translation table
  80.  */
  81. char *ansi_keys[] = {
  82.     "\x1B[A", "\x1B[B", "\x1B[D", "\x1B[C",    /* Arrow keys */
  83.     "\x1BOR", "\x1BOS", "\x1BOP", "\x1BOQ",    /* PgUp, Pgdn, Home, End */
  84.     "\x1BOM", "\x1BOm", "\x1BOp",            /* Keypad '+','-' Insert */
  85.     "\x7F",   "\x08",                        /* Delete & Backspace */
  86.     "\x1BOq", "\x1BOr", "\x1BOs", "\x1BOt",    /* F1, F2, F3 & F4 */
  87.     "\x1BOu", "\x1BOv", "\x1BOw", "\x1BOx",    /* F5, F6, F7 & F8 */
  88.     "\x1BOy", "\x1BOz",                        /* F9 & F10 */
  89.     "\x1BOl", "\x1BOn", 0, 0 };        /* Control: Pgup, Pgdn, Home, End */
  90.  
  91. char *main_menu[] = {        /* Main function menu */
  92.     "Function menu",
  93.     "Download file",
  94.     "Upload file",
  95.     "Kill capture",
  96.     "Perform script",
  97.     "Hangup modem",
  98.     "Clear screen",
  99.     "Configuration",
  100.     "Shell to DOS",
  101.     "Exit to DOS",
  102.     0 };
  103.  
  104. char *config_menu[] = {        /* System configuration menu */
  105.     "General switches",
  106.     "General parameters",
  107.     "Serial port settings",
  108.     "Transfer protocols",
  109.     "Function menu scripts",
  110.     "Video attributes",
  111.     "Load configuration",
  112.     "Save configuration",
  113.     0 }
  114.  
  115. char *switches[] = {        /* General switch names */
  116.     "Sound ALARM in messages",
  117.     "Echo data sent in tty",
  118.     "Echo data sent in scripts",
  119.     "Send LF on ASCII uploads",
  120.     "Send space in NULL lines",
  121.     "Drop DTR+RTS on EXIT" };
  122.  
  123. char *serial_menu[] = {        /* Serial configuration menu */
  124.     "Comm port",
  125.     "Baudrate",
  126.     "Parity",
  127.     "Data bits",
  128.     "Stop bits",
  129.     "Flow control",
  130.     0 }
  131.  
  132. char *setup_form[] = {        /* To set general parameters */
  133.     52<<8|9,
  134.     "\x01\x00\x20Home directory:",
  135.     "\x01\x01\x82Tab spacing:",
  136.     "\x01\x02\x85Modem hangup delay:",
  137.     "\x01\x03\x85String TX char delay:",
  138.     "\x01\x04\x85ASCII Upload char delay:",
  139.     "\x01\x05\x85ASCII Upload line delay:",
  140.     "\x01\x06\x83ASCII Upload sync. char:",
  141.     0 };
  142.  
  143. char *string_form[] = {        /* External protocols & scripts */
  144.     68<<8|10,
  145.     "\x00\x00\x401:",
  146.     "\x00\x01\x402:",
  147.     "\x00\x02\x403:",
  148.     "\x00\x03\x404:",
  149.     "\x00\x04\x405:",
  150.     "\x00\x05\x406:",
  151.     "\x00\x06\x407:",
  152.     "\x00\x07\x408:",
  153.     0 };
  154.  
  155. char *menus[] = {
  156.     "Main TTY screen",
  157.     "Video attribute 1",
  158.     "Video attribute 2",
  159.     "Video attribute 3",
  160.     "Video attribute 4",
  161.     "Video attribute 5",
  162.     "Video attribute 6",
  163.     "Video attribute 7",
  164.     "Status line",
  165.     "Error message box's",
  166.     "String input fields",
  167.     "Main menu's",
  168.     "Sub menu's" };
  169.  
  170. char *commands[] = {        /* Script commands */
  171.     "print", "echo", "assign", "equate", "input", "read", "menu", "if#",
  172.     "ifeq",    "ifne", "ifnot", "if", "goto", "skip", "stop", "call", "chain",
  173.     "send", "scan", "flush", "wait", "upload", "download", "close", "dos",
  174.     "visible", "invisible", "abort", "error", "message", "hangup", "terminal",
  175.     "clear", "config", "exittodos", "rem", 0 };
  176.  
  177. char *operators[] = {        /* Operators in script expression parser */
  178.     "+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>",
  179.     "==", "!=", ">=", "<=", ">", "<",
  180.     0 };
  181.  
  182. /* Common strings */
  183. char uplprompt[] = { "File to UPLOAD" };
  184. char dnlprompt[] = { "File to DOWNLOAD" };
  185. char cnfprompt[] = { "Configuration filename" };
  186. char cnfext[] = { ".CFG" };
  187.  
  188. /* Uart configuration static data tables */
  189. unsigned baudvalue[] =
  190.     { _110,  _300,  _1200,  _2400,  _4800,  _9600,  _19200,  _38400 };
  191. char *baudtext[] =
  192.     { "110", "300", "1200", "2400", "4800", "9600", "19200", "38400", 0 };
  193. char *paritytext[] = { "Odd", "Even", "Mark", "Space", "None", 0 };
  194. char *onetwo[] = { "One", "Two", 0 };
  195. char *onefour[] = { "One", "Two", "Three", "Four", 0 };
  196. char *fiveight[] = { "Five", "Six", "Seven", "Eight", 0 };
  197. char *flowtext[] = { "Disabled", "Enabled", 0 };
  198.  
  199. /* Open window pointers */
  200. struct WINDOW *tty, *status;
  201.  
  202. /* Global window pointer (to retain postion) */
  203. int main_p = 0, config_p = 0, serial_p = 0, proto_p = 0, script_p = 0;
  204.  
  205. /* Misc global variables */
  206. int signals = SET_DTR|SET_RTS|OUTPUT_2;
  207. int key_delay = 0, status_name_ptr = 0;
  208. char *key_ptr = 0, *status_names[10], sent_cr, last_rx;
  209. char cnffile[FSIZE+1] = { "LAPTALK" };
  210. FILE *fp, *log_fp = 0, *upl_fp = 0; /* Upload/Download file pointers */
  211.  
  212. /* Globals used by the script interpreter */
  213. unsigned line, cptr = 0, savenv[3];
  214. char *optr, capture[CAPTURE_SIZE], invisible, abort_flag, interactive = -1;
  215. char buffer[80];
  216.  
  217. extern register message_box(), write_status();
  218.  
  219. /*
  220.  * Main program
  221.  */
  222. main(argc, argv)
  223.     int argc;
  224.     char *argv[];
  225. {
  226.     optr = cnffile;
  227.     for(line=1; line < argc; ++line) {
  228.         tty = argv[line];
  229.         switch((*tty++ << 8)|*tty++) {
  230.             case 'c=' :        /* Specify CONFIG file */
  231.             case 'C=' :
  232.                 optr = tty;
  233.                 break;
  234.             case '-i' :        /* Disable interactive session */
  235.             case '-I' :
  236.                 interactive = 0;
  237.                 break;
  238.             case '-?' :
  239.             case '?' << 8:
  240.                 abort("\nUse: LAPTALK [-i c=file] [script command]\n\nCopyright 1991-1994 Dave Dunfield\nAll rights reserved.\n");
  241.             default:
  242.                 while(argc < 20)
  243.                     argv[argc++] = 0;
  244.                 argc = 0; } }
  245.  
  246.     parse_filename(buffer, cnfext);
  247.     if(fp = fopen(buffer, "rb")) {
  248.         fread(homedir, ansi_keys-homedir, fp);
  249.         fclose(fp); }
  250.  
  251.     status = wopen(0, 24, 80, 1, attrs[STATUS]);
  252.     tty = wopen(0, 0, 80, 24, attrs[TTY]);
  253.  
  254.     if(!fp)
  255.         message_box("Unable to open CONFIG file: %s", buffer);
  256.  
  257.     update_status();
  258.     w_puts(" Press CTRL-HOME or CTRL-END for menu", status);
  259.  
  260.     open_comm();
  261.     IOB_size = 512;
  262.  
  263.     if(!argc)
  264.         script(&argv[line-1]);
  265.  
  266.     while(interactive) {
  267.         ansi_term();
  268.         if(!wmenu(5, 3, attrs[SETUP1], main_menu, &main_p)) switch(main_p) {
  269.             case 0 :    /* Fast access script */
  270.                 if(optr = file_menu(scripts, &script_p, 0)) {
  271.                     parse_args(buffer);
  272.                     script(buffer); }
  273.                 break;
  274.             case 1 :    /* Download */
  275.                 if(optr = file_menu(protocols, &proto_p, 0))
  276.                     file_transfer(0, 0);
  277.                 break;
  278.             case 2 :    /* Upload */
  279.                 if(optr = file_menu(protocols, &proto_p, 0))
  280.                     file_transfer(-1, 0);
  281.                 break;
  282.             case 3 :    /* Close capture */
  283.                 if(log_fp)
  284.                     fclose(log_fp);
  285.                 log_fp = 0;
  286.                 update_status();
  287.                 break;
  288.             case 4 :    /* Script by name */
  289.                 if(!get_string("Script", optr = scriptfile, FSIZE)) {
  290.                     parse_args(buffer);
  291.                     script(buffer); }
  292.                 break;
  293.             case 5 :    /* Hangup */
  294.                 hangup();
  295.                 break;
  296.             case 6 :    /* Clear screen */
  297.                 wclwin();
  298.                 break;
  299.             case 7 :    /* Configure */
  300.                 configure();
  301.                 break;
  302.             case 8 :    /* Shell to DOS */
  303.                 doshell(0);
  304.                 break;
  305.             case 9 :    /* Exit */
  306.                 interactive = 0; } }
  307.  
  308.     if(log_fp)
  309.         fclose(log_fp);
  310.     if(hangmdm) {
  311.         signals &= ~(SET_DTR|SET_RTS);
  312.         open_comm(); }
  313.     Cclose();
  314.     wclose();
  315.     wclose();
  316. }
  317.  
  318. /*
  319.  * Display a message in a box
  320.  */
  321. register message_box(args)
  322.     unsigned args;
  323. {
  324.     unsigned *ptr, l;
  325.     char buffer[80];
  326.  
  327.     ptr = nargs() * 2 + &args;
  328.     _format_(buffer, ptr);
  329.  
  330.     l = strlen(buffer)+16;
  331.     wopen((80-l)/2, 10, l+2, 3, attrs[ERROR]);
  332.     wcursor_off();
  333.     wprintf(" %s (Press ENTER) ", buffer);
  334.     if(alarm) wputc(7);
  335.     while(wgetc() != '\n');
  336.     wclose();
  337. }
  338.  
  339. /*
  340.  * Write a message into the status line
  341.  */
  342. register write_status(args)
  343.     unsigned args;
  344. {
  345.     unsigned *ptr;
  346.     char buffer[80];
  347.  
  348.     ptr = nargs() * 2 + &args;
  349.     _format_(buffer, ptr);
  350.     w_printf(status,"\r%s", buffer);
  351.     w_cleow(status);
  352. }
  353.  
  354. /*
  355.  * Update status line
  356.  */
  357. update_status()
  358. {
  359.     int i;
  360.     w_printf(status,"\rCOM%u: %5s-%u%c%u %c \xB3 %3s \xB3",
  361.         com_port+1, baudtext[baud], dbits+5, *paritytext[parity], sbits+1,
  362.         *flowtext[flow], log_fp ? "Cap" : "");
  363.     for(i=0; i < status_name_ptr; ++i)
  364.         w_printf(status," %s", status_names[i]);
  365.     w_cleow(status);
  366. }
  367.  
  368. /*
  369.  * Open comm port with correct settings
  370.  */
  371. open_comm()
  372. {
  373.     int mode;
  374.  
  375.     /* Calculate the communications parameter value */
  376.     mode =    ((parity << 4) & 0x30) |    /* parity type */
  377.             (dbits & 0x03) |            /* # data bits */
  378.             ((sbits << 2) & 0x04) |        /* # stop bits */
  379.             ((parity < 4) << 3);        /* parity enable */
  380.  
  381.     /* Open the communications port */
  382.     if(Copen(com_port+1, baudvalue[baud], mode, signals)) {
  383.         message_box("Cannot open COM port %u!", com_port+1);
  384.         return 0; }
  385.  
  386.     /* Remove transparency if XON/XOFF flow control */
  387.     disable();
  388.     Cflags = (flow) ? Cflags & ~TRANSPARENT : Cflags | TRANSPARENT;
  389.     enable();
  390.  
  391.     return -1;
  392. }
  393.  
  394. /*
  395.  * Hangup the modem
  396.  */
  397. hangup()
  398. {
  399.     write_status("Hanging up the modem...");
  400.     signals &= ~(SET_DTR|SET_RTS);
  401.     open_comm();
  402.     wait_clear(hangup_delay);
  403.     signals |= (SET_DTR|SET_RTS);
  404.     open_comm();
  405.     update_status();
  406. }
  407.  
  408. /*
  409.  * Write a string to the comm port
  410.  */
  411. Cputs(ptr)
  412.     char *ptr;
  413. {
  414.     int c;
  415.     unsigned timeout;
  416.  
  417.     while(*ptr) {
  418.         timeout = key_string_delay;
  419.         do {
  420.             if((c = Ctestc()) != -1)
  421.                 receive_data(c);
  422.             if((c = Ctestc()) != -1)
  423.                 receive_data(c); }
  424.         while(timeout--);
  425.         Cwrite(*ptr++); }
  426.     testabort();
  427. }
  428.  
  429. /*
  430.  * Write char to comm port with echo if enabled
  431.  */
  432. Cwrite(c)
  433.     int c;
  434. {
  435.     Cputc(c);
  436.     if(echosnd)
  437.         wputc(c);
  438. }
  439.  
  440.  
  441. /*
  442.  * Get a string from the console
  443.  */
  444. get_string(prompt, name, length)
  445.     char *prompt, *name;
  446.     int length;
  447. {
  448.     int i, j;
  449.  
  450.     i = (j = strlen(prompt))+length+7;
  451.     wopen((80-i)/2, 10, i, 3, attrs[STRING]);
  452.     for(;;) {
  453.         wgotoxy(1, 0);
  454.         wprintf("%s ? ", prompt);
  455.         switch(wgets(j+4, 0, name, length)) {
  456.             case 0x1B :        /* Exit */
  457.                 wclose();
  458.                 return -1;
  459.             case '\n' :        /* Select */
  460.                 wclose();
  461.                 return 0; } }
  462. }
  463.  
  464. /*
  465.  * Open a file with options
  466.  */
  467. open_file(filename, options)
  468.     char *filename, *options;
  469. {
  470.     int n, p, c, i;
  471.     char *names[100], namebuf[1000], *nptr, *ptr, *ptr1;
  472.  
  473.     for(ptr = filename; i = *ptr; ++ptr)
  474.         if((i == '*') || (i == '?'))
  475.             break;
  476.     if(i) {
  477.         if(find_first(filename, n = 0, nptr = namebuf, &i, &i, &i, &i, &i)) {
  478.             message_box("No files found matching: '%s'", filename);
  479.             return 0; }
  480.         wopen(13, 5, 53, 12, attrs[STRING]);
  481.         wcursor_off();
  482.         do {
  483.             for(i=0; i < n; ++i)
  484.                 if(strcmp(names[i], nptr) == 1)
  485.                     break;
  486.             for(c = ++n; c > i; --c)
  487.                 names[c] = names[c-1];
  488.             names[i] = nptr;
  489.             while(*nptr++); }
  490.         while((n < (sizeof(names)/2)) && !find_next(nptr, &i, &i, &i, &i, &i));
  491.         for(i=n; i < (sizeof(names)/2); ++i)
  492.             names[i] = "";
  493.  
  494.         c = p = 0;
  495.         for(;;) {
  496.             for(i=0; i < 40; ++i) {
  497.                 wgotoxy((i%4)*13, i/4);
  498.                 *W_OPEN = (i == c) ? ((*W_OPEN >> 4)|(*W_OPEN << 4)) : attrs[STRING];
  499.                 wputf(names[i+p], 12); }
  500.             switch(wgetc()) {
  501.                 case 0x1B :
  502.                     wclose();
  503.                     return 0;
  504.                 case '\n' :
  505.                     ptr = ptr1 = filename;
  506.                     while(i = *ptr++) {
  507.                         if((i == '\\') || (i == ':'))
  508.                             ptr1 = ptr; }
  509.                     strcpy(ptr1, names[p+c]);
  510.                     wclose();
  511.                     goto open_file;
  512.                 case _KRA : i = c + 1; goto position;
  513.                 case _KLA : i = c - 1; goto position;
  514.                 case _KUA : i = c - 4; goto position;
  515.                 case _KDA : i = c + 4;
  516.                 position:
  517.                     if(i < 0) {
  518.                         c = 0;
  519.                         if((p - 4) >= 0) {
  520.                             c = i + 4;
  521.                             p -= 4; }
  522.                         break; }
  523.                     if(i >= 40) {
  524.                         if((p + 40) < n) {
  525.                             i -= 4;
  526.                             p += 4; } }
  527.                     c = ((p + i) < n) ? i : (n - p) - 1; } } }
  528.  
  529. open_file:
  530.     if(!options)        /* Solve wildcards only ... don't open */
  531.         return -1;
  532.     if(!(fp = fopen(filename, options)))
  533.         message_box("Unable to access: '%s'", filename);
  534.     return fp;
  535. }
  536.  
  537. /*
  538.  * Configuration menu
  539.  */
  540. configure()
  541. {
  542.     int c, i, f, b;
  543.     char *ptr;
  544.  
  545.     wopen(5, 3, 30, (sizeof(config_menu)/2)+1, WSAVE);
  546.     wcursor_off();
  547.     while(!wmenu(5, 3, attrs[SETUP2], config_menu, &config_p)) switch(config_p) {
  548.         case 0 :    /* General switches */
  549.             ptr = &alarm;
  550.             wopen(28, 3, 40, (sizeof(switches)/2)+2, attrs[SETUP1]);
  551.             for(;;) {
  552.                 for(i=0; i < (sizeof(switches)/2); ++i) {
  553.                     wgotoxy(0, i);
  554.                     wprintf("%u: %-31s= %c", i+1, switches[i], ptr[i] ? 'Y' : 'N'); }
  555.             if((i = wgetc()) == 0x1B) {
  556.                 wclose();
  557.                 break; }
  558.             if((i -= '1') < (sizeof(switches)/2))
  559.                 ptr[i] = ptr[i] ? 0 : -1; }
  560.             break;
  561.         case 1 :     /* General parameters */
  562.             wform(28, 3, attrs[SETUP1], setup_form, homedir, &tab_size, &hangup_delay,
  563.                 &key_string_delay, &upl_char_delay, &upl_line_delay, &upl_sync_char);
  564.             break;
  565.         case 2 :    /* Serial port setup */
  566.             wopen(28, 3, 30, (sizeof(serial_menu)/2)+1, WSAVE);
  567.             while(!wmenu(28, 3, attrs[SETUP2], serial_menu, &serial_p)) {
  568.                 switch(serial_p) {
  569.                     case 0 : wmenu(42, 3, attrs[SETUP1], onefour, &com_port);    break;
  570.                     case 1 : wmenu(42, 3, attrs[SETUP1], baudtext, &baud);        break;
  571.                     case 2 : wmenu(42, 3, attrs[SETUP1], paritytext, &parity);    break;
  572.                     case 3 : wmenu(42, 3, attrs[SETUP1], fiveight, &dbits);        break;
  573.                     case 4 : wmenu(42, 3, attrs[SETUP1], onetwo, &sbits);        break;
  574.                     case 5 : wmenu(42, 3, attrs[SETUP1], flowtext, &flow); }
  575.                 update_status(); }
  576.             open_comm();
  577.             wclose();
  578.             break;
  579.         case 3 :    /* Protocol setup */
  580.             wform(5, 13, attrs[SETUP1], string_form, protocols[0], protocols[1],
  581.                 protocols[2], protocols[3], protocols[4], protocols[5],
  582.                 protocols[6], protocols[7]);
  583.             break;
  584.         case 4 :    /* Script setup */
  585.             wform(5, 13, attrs[SETUP1], string_form, scripts[0], scripts[1],
  586.                 scripts[2], scripts[3], scripts[4], scripts[5], scripts[6],
  587.                 scripts[7]);
  588.             break;
  589.         case 5 :    /* Video attributes */
  590.             i = 0;
  591.             do {
  592.                 f = attrs[i] & 0x0F;
  593.                 b = (attrs[i] >> 4) & 0x0F;
  594.                 wopen(28, 3, 40, 9, WSAVE|WCOPEN|WBOX2|(b<<4)|f);
  595.                 *W_OPEN = (f << 4) + b;
  596.                 wprintf("%-38s\n\n", menus[i]);
  597.                 *W_OPEN = (b << 4) + f;
  598.                 wputs("Left/Right = Foreground\nUp/Down    = Background\n");
  599.                 wputs("PgUp/PgDn  = Select window\n\nPress ESCAPE to exit.");
  600.                 c = wgetc();
  601.                 wclose();
  602.                 switch(c) {
  603.                     case _KRA : f = (f+1) & 0x0F; goto newattr;
  604.                     case _KLA : f = (f-1) & 0x0F; goto newattr;
  605.                     case _KDA : b = (b+1) & 0x0F; goto newattr;
  606.                     case _KUA : b = (b-1) & 0x0F;
  607.                     newattr:
  608.                         attrs[i] = (attrs[i] & 0xff00) | (b << 4) | f;
  609.                         break;
  610.                     case _KPD : if(++i >= (sizeof(menus)/2)) i = 0;    break;
  611.                     case _KPU : if(--i < 0) i = (sizeof(menus)/2)-1; } }
  612.             while(c != 0x1B);
  613.             break;
  614.         case 6 :    /* Load configuration */
  615.             if(get_string(cnfprompt, optr = cnffile, FSIZE))
  616.                 break;
  617.             parse_filename(buffer, cnfext);
  618.             if(open_file(buffer, "rb")) {
  619.                 fread(homedir, ansi_keys-homedir, fp);
  620.                 fclose(fp);
  621.                 open_comm(); }
  622.             break;
  623.         case 7 :    /* Save configuration */
  624.             if(get_string(cnfprompt, optr = cnffile, FSIZE))
  625.                 break;
  626.             parse_filename(buffer, cnfext);
  627.             if(open_file(buffer, "wb")) {
  628.                 fwrite(homedir, ansi_keys-homedir, fp);
  629.                 fclose(fp); }
  630.         }
  631.     wclose();
  632.     update_config();
  633. }
  634.  
  635. /*
  636.  * Update the displays to indiate a new configuration
  637.  */
  638. update_config()
  639. {
  640.     if(*tty != (*attrs & 0xff)) {
  641.         *tty = *attrs;
  642.         w_clwin(tty); }
  643.     *status = attrs[STATUS];
  644.     update_status();
  645. }
  646.  
  647. /*
  648.  * Terminal mode using ANSI (VT100) emulation
  649.  */
  650. ansi_term()
  651. {
  652.     char c, xy_flag;
  653.     unsigned x, y, state, value, parm, parms[5];
  654.  
  655.     xy_flag = -1;        /* Force initial cursor update */
  656.     state = 0;            /* Not receiving a control sequence */
  657.     for(;;) {
  658.         /* Process any input from the comm port */
  659.         if((c = Ctestc()) != -1) {
  660.             last_rx = c;
  661. ansi_out:
  662.             if(log_fp && ((c >= ' ') || (c == '\t') || (c == '\n')))
  663.                 putc(c, log_fp);
  664.             xy_flag = -1;
  665.             if(c == 0x1B) {                /* Begin escape sequence */
  666.                 state = 1;
  667.                 parms[0] = parms[1] = value = parm = 0; }
  668.             else switch(state) {
  669.                 case 1 :                /* Escape already received */
  670.                     if(c == '[') {
  671.                         state = 2;
  672.                         break; }
  673.                     state = 0;
  674.                 case 0 :                /* No special processing */
  675.                     if(c == '\t') {
  676.                         do 
  677.                             wputc(' ');
  678.                         while(tty[6] % tab_size);
  679.                         break; }
  680.                     wputc(c);
  681.                     break;
  682.                 case 2 :                /* Waiting for numeric parms */
  683.                     if(isdigit(c)) {
  684.                         value = (value * 10) + (c - '0');
  685.                         break; }
  686.                     parms[parm++] = value;    /* More to come */
  687.                     if(c == ';') {
  688.                         value = 0;
  689.                         break; }
  690.                     state = 0;
  691.                     switch(c) {
  692.                         case 'H' :        /* Cursor position (1) */
  693.                         case 'f' :        /* Cursor position (2) */
  694.                             if(y = parms[0])
  695.                                 --y;
  696.                             if(x = parms[1])
  697.                                 --x;
  698.                             wgotoxy(x, y);
  699.                             break;
  700.                         case 'J' :        /* Erase in display */
  701.                             x = tty[6]; y = tty[7];
  702.                             value ? wclwin() : wcleow();
  703.                             tty[6] = x; tty[7] = y;
  704.                             break;
  705.                         case 'K' :        /* Erase in line */
  706.                             if(value)
  707.                                 tty[6] = 0;
  708.                             wcleol();
  709.                             break;
  710.                         case 'm' :        /* Select attributes */
  711.                             if((x = parms[0]) > 7)
  712.                                 x = 0;
  713.                             *tty = attrs[x]; } } }
  714.         else if(xy_flag) {                /* Cursor has moved */
  715.             wupdatexy();
  716.             xy_flag = 0; }
  717.  
  718.         /* Process any input from the keyboard */
  719.         if(c = get_key()) {
  720.             if(c == EOF)
  721.                 return;
  722.             Cputc(c);
  723.             if(echotty)
  724.                 goto ansi_out; } }
  725.  
  726. }
  727.  
  728. /*
  729.  * Read a key from the keyboard
  730.  */
  731. get_key()
  732. {
  733.     int c;
  734.  
  735.     if(key_delay) {
  736.         --key_delay;
  737.         return 0; }
  738.  
  739.     if(upl_fp) {
  740.         if(c = wtstc()) switch(c) {
  741.             case 0x1B :
  742.                 abort_flag = -1;
  743.                 goto abort;
  744.             case ' ' :
  745.                 last_rx = upl_sync_char; }
  746.         key_delay = upl_char_delay;
  747.         switch(sent_cr) {
  748.             case ' ' :            /* Expanded NULL line */
  749.                 goto sendcr;
  750.             case '\r' :            /* Just sent return */
  751.                 if(sendlf)
  752.                     return sent_cr = 0x0A;
  753.             case 0x0A :            /* Just sent line-feed */
  754.                 if(upl_sync_char) {
  755.                     if(last_rx != upl_sync_char)
  756.                         return key_delay = 0; }
  757.                 sent_cr = -1; }
  758.         if((c = getc(upl_fp)) != EOF) {
  759.             if(c == '\n') {
  760.                 if(sendnull && sent_cr)
  761.                     return sent_cr = ' ';
  762. sendcr:            key_delay = upl_line_delay;
  763.                 return sent_cr = '\r'; }
  764.             sent_cr = 0;
  765.             return c; }
  766. abort:    fclose(upl_fp);
  767.         upl_fp = sent_cr = 0;
  768.         update_status(); }
  769.     if(key_ptr) {
  770.         if(c = *key_ptr++) {
  771.             key_delay = key_string_delay;
  772.             return c; }
  773.         key_ptr = 0; }
  774.     if((c = wtstc()) & 0x80) {
  775.         return (key_ptr = ansi_keys[c & 0x7f]) ? 0 : -1; }
  776.     return (c == '\n') ? '\r' : c;
  777. }
  778.  
  779. /*
  780.  * Execute a sub-shell
  781.  */
  782. doshell(command)
  783.     char *command;
  784. {
  785.     char comspec[65], tail[80];
  786.  
  787.     if(!getenv("COMSPEC", comspec)) {
  788.         message_box("Cannot locate COMSPEC");
  789.         return; }
  790.     *tail = 0;
  791.     if(command)
  792.         concat(tail, "/C ", command);
  793.     wopen(0, 0, 80, 25, WSAVE|WCOPEN|0x07);
  794.     wupdatexy();
  795.     exec(comspec, tail);
  796.     wclose();
  797. }
  798.  
  799. /*
  800.  * Perform a file transfer
  801.  */
  802. file_transfer(upload, name)
  803.     char upload, *name;
  804. {
  805.     int i, c;
  806.     char buffer[6], cmd[100], zap, wait, ascii;
  807.     char *ptr1, *ptr2, *ptr3;
  808.  
  809.     wait = zap = ascii = i = 0;
  810.     ptr1 = parse_filename(cmd, ".COM");
  811.  
  812.     ptr2 = ++ptr1;
  813.     while(c = *optr++) {
  814.         if(c == '\\') switch(c = *optr++) {
  815.             case 'Z' : zap = -1;    continue;                /* Zap screen */
  816.             case 'W' : wait = -1;    continue;                /* Wait after run */
  817.             case 'A' : ascii = -1;    continue;                /* ASCII transfer */
  818.             case 'P' : ptr3 =paritytext[parity];goto copy;    /* Parity */
  819.             case 'B' : ptr3 = baudtext[baud];    goto copy;    /* Baudrate */
  820.             case 'H' : ptr3 = homedir;            goto copy;    /* Home dir */
  821.             case 'N' : c = dbits + 5;            goto wrnum;    /* Data bits */
  822.             case 'S' : c = sbits + 1;            goto wrnum;    /* Stop bits */
  823.             case 'C' : c = com_port + 1;                    /* Comm port */
  824.             wrnum:
  825.                 sprintf(ptr3 = buffer,"%u", c);
  826.             copy:
  827.                 while(c = *ptr3++)
  828.                     *ptr1++ = c;
  829.                 continue;
  830.             case 'G' :        /* Upload filename */
  831.             case 'Y' :        /* Upload with wildcards */
  832.                 if(!upload)
  833.                     continue;
  834.             case 'F' :        /* Filename */
  835.             case 'X' :        /* Allow wildcards */
  836.                 if(!(ptr3 = name)) {
  837.                     if(get_string(upload ? uplprompt : dnlprompt, ptr3 = name = filename, FSIZE))
  838.                         return; }
  839.                 if(((c == 'F') || (c == 'G')) && !open_file(name, 0))
  840.                     return;
  841.                 goto copy;
  842.             case 'U' :        /* Upload string */
  843.                 while((c = *optr++) && (c != '\\'))
  844.                     if(upload)
  845.                         *ptr1++ = c;
  846.                 continue;
  847.             case 'D' :        /* Download string */
  848.                 while((c = *optr++) && (c != '\\'))
  849.                     if(!upload)
  850.                         *ptr1++ = c;
  851.                 continue; }
  852.         *ptr1++ = c; }
  853.     *ptr1 = 0;
  854.  
  855.     /* Process ASCII transfers */
  856.     if(ascii) {
  857.         while(isspace(*ptr2)) ++ptr2;
  858.         if(upload) {
  859.             if(upl_fp = open_file(ptr2, "r"))
  860.                 write_status("ASCII upload of '%s'...", ptr2); }
  861.         else {
  862.             if(log_fp)
  863.                 fclose(log_fp);
  864.                 log_fp = open_file(ptr2, "w");
  865.                 update_status(); }
  866.         return; }
  867.  
  868.     /* Execute the external protocol */
  869.     write_status("%s of '%s'...", upload ? "Upload" : "Download", name);
  870.     Cclose();
  871.     if(zap) wopen(0, 0, 80, 25, WSAVE|WCOPEN|0x07);
  872.     wupdatexy();
  873.     i = exec(cmd, ptr2);
  874.     if(wait) {
  875.         write_status("Press enter to continue...");
  876.         while(wtstc() != '\n'); }
  877.     if(zap) wclose();
  878.     open_comm();
  879.     update_status();
  880.     if(i)
  881.         message_box("Error %u returned from '%s'!", i, cmd);
  882. }
  883.  
  884. /*
  885.  * Build an entry from a file list
  886.  */
  887. file_menu(files, pointer, name)
  888.     char files[NFILES][FWIDTH], *name;
  889.     int *pointer;
  890. {
  891.     int i, j, c;
  892.     char *names[NFILES+1], *pptr[NFILES], buffer[100], *ptr, *ptr1, *ptr2;
  893.  
  894.     /* Build menu from filenames */
  895.     ptr1 = buffer;
  896.     for(i=j=0; i < NFILES; ++i) {
  897.         if(*(ptr = files[i])) {
  898.             pptr[j] = ptr;
  899.             names[j++] = ptr2 = ptr1;
  900.             while(c = *ptr++) {
  901.                 if(isspace(c) || (c == ';'))
  902.                     break;
  903.                 else if((c == '\\') || (c == ':'))
  904.                     ptr1 = ptr2;
  905.                 else
  906.                     *ptr1++ = c; }
  907.             *ptr1++ = 0; }
  908.             if(name && strbeg(ptr2, name)) {
  909.                 ptr = ptr1 = pptr[j-1];
  910.                 goto strip_name; } }
  911.     names[j] = 0;
  912.  
  913.     if(!j) {
  914.         message_box("No selections configured!");
  915.         return 0; }
  916.  
  917.     if(wmenu(5, 3, attrs[SETUP1], names, pointer))
  918.         return 0;
  919.  
  920.     /* Strip off any leading name */
  921.     ptr = ptr1 = pptr[*pointer];
  922. strip_name:
  923.     while((c = *ptr++) && !isspace(c)) {
  924.         if(c == ';')
  925.             return ptr; }
  926.     return ptr1;
  927. }
  928.  
  929. /*
  930.  * Execute a script command file
  931.  */
  932. script(argv)
  933.     char *argv[];
  934. {
  935.     unsigned c, i;
  936.     char buffer[80], buffer1[80], *ptr, *ptr1;
  937.     char variables[NUM_VARS][50];
  938.     FILE *sfp;
  939.  
  940. chain_script:
  941.     abort_flag = invisible = 0;
  942.     status_names[status_name_ptr++] = optr = argv[0];
  943.     parse_filename(buffer, ".SCR");
  944.     if(!(sfp = open_file(buffer, "r")))
  945.         goto exit1;
  946.     update_status();
  947.  
  948.     /* zero out the variables */
  949.     for(line=i=0; i < NUM_VARS; ++i)
  950.         *variables[i] = 0;
  951.     flush_capture(0);
  952.  
  953.     while(fgets(optr = buffer, sizeof(buffer), sfp)) {
  954.         ++line;
  955.         /* Skip any label */
  956.         if(skip_blanks() == ':')
  957.             while(*optr && !isspace(*optr))
  958.                 ++optr;
  959.  
  960. next_cmd_string:
  961.         wupdatexy();
  962.         /* Substitute any variables etc. */
  963.         ptr = buffer1;
  964.         while((c = *optr++) && (c != ';')) {
  965.             if(c == '\\') switch(c = *optr++) {
  966.                 case 'b' :    c = 0x08;    break;
  967.                 case 'd' :    c = 0x7F;    break;
  968.                 case 'e' :    c = 0x1B;    break;
  969.                 case 'r' :    c = 0x0D;    break;
  970.                 case '#' :
  971.                     c = 0;
  972.                     while(isdigit(*optr))
  973.                         c = (c*10) + (*optr++ - '0');
  974.                     break;
  975.                 case 's' :
  976.                     sprintf(ptr, "%u", Csignals());
  977.                     while(*++ptr);
  978.                     continue;
  979.                 default:
  980.                     if((i = c - '0') < 10)
  981.                         ptr1 = argv[i];
  982.                     else if((i = c - 'A') < NUM_VARS)
  983.                         ptr1 = variables[i];
  984.                     else if(c == 'n')
  985.                         ptr1 = "\r\n";
  986.                     else if(c == 'h')
  987.                         ptr1 = homedir;
  988.                     else
  989.                         break;
  990.                     if(ptr1) while(*ptr1)
  991.                         *ptr++ = *ptr1++;
  992.                     continue; }
  993.             else if(c == '^')
  994.                 c = *optr++ & 0x1f;
  995.             *ptr++ = c; }
  996.         while(isspace(*--ptr) && (ptr >= buffer1));
  997.         *++ptr = 0;
  998.         optr = buffer1;
  999.  
  1000. continue_command:
  1001.         testabort();
  1002.         if(abort_flag)
  1003.             goto exit;
  1004.         if(*optr) switch(i = lookup(commands)) {
  1005.             case 0 :    /* Print */
  1006.                 wprintf("%s\n\r",optr);
  1007.                 break;
  1008.             case 1 :    /* Echo */
  1009.                 wputs(optr);
  1010.                 break;
  1011.             case 2 :    /* Assign */
  1012.             case 3 :    /* Equate */
  1013.             case 4 :    /* Input */
  1014.             case 5 :    /* Read */
  1015.             case 6 :    /* Menu */
  1016.                 if((c = *optr++ - 'A') >= NUM_VARS) {
  1017.                     script_error("Invalid variable name");
  1018.                     goto exit; }
  1019.                 skip_blanks();
  1020.                 ptr = variables[c];
  1021.                 switch(i) {
  1022.                     case 2 : strcpy(ptr, optr);             break;
  1023.                     case 3 : sprintf(ptr, "%d", eval());    break;
  1024.                     case 4 : 
  1025.                         if(get_string(optr, ptr, sizeof(variables[0])-1))
  1026.                             goto exit;
  1027.                         break;
  1028.                     case 5 :
  1029.                         Cputs(optr);
  1030.                         i = 0;
  1031.                         do {
  1032.                             do
  1033.                                 if(testabort()) goto exit;
  1034.                             while((c = Ctestc()) == -1);
  1035.                             if((c == '\b') || (c == 0x7f)) {
  1036.                                 if(i) {
  1037.                                     --i;
  1038.                                     Cputs("\b \b"); } }
  1039.                             else if(c >= ' ')
  1040.                                 Cwrite(ptr[i++] = c); }
  1041.                         while(c != '\r');
  1042.                         ptr[i] = 0;
  1043.                         Cputs("\n\r");
  1044.                         break;
  1045.                     case 6 :
  1046.                         parse_args(buffer);
  1047.                         c = 0;
  1048.                         sprintf(ptr,"%d", wmenu(5, 3, attrs[SETUP1], buffer, &c) ?
  1049.                             -1 : c); }
  1050.                 break;
  1051.             case 7 :    /* If# */
  1052.                 if(eval()) {
  1053.                     expect(':');
  1054.                     goto continue_command; }
  1055.                 break;
  1056.             case 8 :    /* Ifeq */
  1057.             case 9 :    /* ifne */
  1058.                 parse_string(buffer);
  1059.                 parse_string(buffer+40);
  1060.                 expect(':');
  1061.                 if(i == 8) {
  1062.                     if(!strcmp(buffer, buffer+40))
  1063.                         goto continue_command; }
  1064.                 else {
  1065.                     if(strcmp(buffer, buffer+40))
  1066.                         goto continue_command; }
  1067.                 break;
  1068.             case 10 :    /* Ifnot */
  1069.                 parse_string(buffer);
  1070.                 expect(':');
  1071.                 if(!search_buffer(buffer))
  1072.                     goto continue_command;
  1073.                 break;
  1074.             case 11 :    /* If */
  1075.                 parse_string(buffer);
  1076.                 expect(':');
  1077.                 if(search_buffer(buffer))
  1078.                     goto continue_command;
  1079.                 break;
  1080.             case 12 :    /* Goto */
  1081.                 if(*optr == '+')
  1082.                     ++optr;
  1083.                 else {
  1084.                     rewind(sfp);
  1085.                     line = 0; }
  1086.                 ptr = optr;
  1087.             search_next:
  1088.                 while(fgets(optr = buffer, sizeof(buffer), sfp)) {
  1089.                     ++line;
  1090.                     if(skip_blanks() == ':') {
  1091.                         ++optr;
  1092.                         ptr1 = ptr;
  1093.                         while(*optr && !isspace(*optr)) {
  1094.                             if(*optr++ != *ptr1++)
  1095.                                 goto search_next; }
  1096.                         if(isspace(*ptr1) || !*ptr1)
  1097.                             goto next_cmd_string; } }
  1098.                 script_error("Label not found");
  1099.             case 13 :    /* Skip */
  1100.                 for(i = eval(); i; --i)
  1101.                     if(!fgets(buffer, sizeof(buffer), sfp))
  1102.                         goto exit;
  1103.             case 14 :    /* Stop */
  1104.                 goto exit;
  1105.             case 15 :    /* Call */
  1106.                 i = line;
  1107.                 c = invisible;
  1108.                 parse_args(buffer);
  1109.                 script(buffer);
  1110.                 invisible = c;
  1111.                 line = i;
  1112.                 break;
  1113.             case 16 :    /* Chain */
  1114.                 fclose(sfp);
  1115.                 parse_args(argv);
  1116.                 --status_name_ptr;
  1117.                 goto chain_script;
  1118.             case 17 :    /* Send */
  1119.                 Cputs(optr);
  1120.                 break;
  1121.             case 18 :    /* Scan */
  1122.                 flush_capture(0);
  1123.                 if(parse_string(buffer))
  1124.                     if(!wait_string(buffer, eval()+1))
  1125.                         if(*optr) {
  1126.                             expect(':');
  1127.                             goto continue_command; }
  1128.                 break;
  1129.             case 19 :    /* Flush */
  1130.                 while((c = Ctestc()) != -1)
  1131.                     receive_data(c);
  1132.                 flush_capture(*buffer ? buffer : 0);
  1133.                 break;
  1134.             case 20 :    /* Wait */
  1135.                 wait_clear(eval());
  1136.                 break;
  1137.             case 21 :    /* Upload */
  1138.             case 22 :    /* Download */
  1139.                 ptr = optr;
  1140.                 while((c = *optr) && !isspace(c)) ++optr;
  1141.                 if(c)
  1142.                     *optr++ = 0;
  1143.                 ptr1 = skip_blanks() ? optr : 0;
  1144.                 if(optr = file_menu(protocols, &proto_p, ptr)) {
  1145.                     if(i == 21) {
  1146.                         file_transfer(-1, ptr1);
  1147.                         while(upl_fp) {
  1148.                             while((c = Ctestc()) != -1)
  1149.                                 receive_data(c);
  1150.                             if(c = get_key())
  1151.                                 Cwrite(c); } }
  1152.                     else
  1153.                         file_transfer(0, ptr1); }
  1154.                 break;
  1155.             case 23 :    /* Close */
  1156.                 if(log_fp) {
  1157.                     fclose(log_fp);
  1158.                     log_fp = 0; }
  1159.                 update_status();
  1160.                 break;
  1161.             case 24 :    /* Dos */
  1162.                 doshell(optr);
  1163.                 break;
  1164.             case 25 :    invisible = 0;    break;    /* Visible */
  1165.             case 26 :    invisible = -1;    break;    /* Invisible */
  1166.             case 27 :    /* Abort */
  1167.                 script_error(optr);
  1168.                 break;
  1169.             case 28 :    /* Error */
  1170.                 abort_flag = -1;
  1171.             case 29 :    /* Message */
  1172.                 message_box(optr);
  1173.                 break;
  1174.             case 30 :    /* Hangup */
  1175.                 hangup();
  1176.                 break;
  1177.             case 31 :    /* Terminal */
  1178.                 ansi_term();
  1179.                 break;
  1180.             case 32 :    /* Clear */
  1181.                 wclwin();
  1182.                 break;
  1183.             case 33 :    /* Config */
  1184.                 parse_filename(buffer, cnfext);
  1185.                 if(open_file(buffer, "rb")) {
  1186.                     fread(homedir, ansi_keys-homedir, fp);
  1187.                     fclose(fp);
  1188.                     open_comm();
  1189.                     update_config(); }
  1190.                 break;
  1191.             case 34 :    /* Exittodos */
  1192.                 interactive = 0;
  1193.                 abort_flag = -1;
  1194.                 goto exit;
  1195.             default:
  1196.                 script_error("Unknown command");
  1197.                 goto exit;
  1198.             case 35 : } } /* Remark */
  1199. exit:
  1200.     fclose(sfp);
  1201. exit1:
  1202.     if(upl_fp) {
  1203.         fclose(upl_fp);
  1204.         upl_fp = 0; }
  1205.     --status_name_ptr;
  1206.     update_status();
  1207. }
  1208.  
  1209. /*
  1210.  * Evaluate an expression and return its numeric value
  1211.  */
  1212. eval()
  1213. {
  1214.     int o, v, v1;
  1215.     char vflag, mflag;
  1216.  
  1217.     v1 = o = 0;
  1218.     do {
  1219.         if(!*optr) {
  1220.             script_error("Incomplete expression");
  1221.             return 0; }
  1222.         mflag = vflag = v = 0;
  1223.         if(*optr == '-') {
  1224.             ++optr;
  1225.             mflag = -1; }
  1226.         if(*optr == '(') {
  1227.             ++optr;
  1228.             v = eval();
  1229.             if(expect(')'))
  1230.                 return; }
  1231.         else {
  1232.             while(isdigit(*optr)) {
  1233.                 v = (v * 10) + (*optr++ - '0');
  1234.                 vflag = -1; }
  1235.             if(!vflag) {
  1236.                 script_error("Invalid number");
  1237.                 return 0; } }
  1238.         if(mflag) v = -v;
  1239.         switch(o) {
  1240.             case 0 : v1 += v;        break;
  1241.             case 1 : v1 -= v;        break;
  1242.             case 2 : v1 *= v;        break;
  1243.             case 3 : v1 /= v;        break;
  1244.             case 4 : v1 %= v;        break;
  1245.             case 5 : v1 &= v;        break;
  1246.             case 6 : v1 |= v;        break;
  1247.             case 7 : v1 ^= v;        break;
  1248.             case 8 : v1 <<= v;        break;
  1249.             case 9 : v1 >>= v;        break;
  1250.             case 10: v1 = v1 == v;    break;
  1251.             case 11: v1 = v1 != v;    break;
  1252.             case 12: v1 = v1 >= v;    break;
  1253.             case 13: v1 = v1 <= v;    break;
  1254.             case 14: v1 = v1 > v;    break;
  1255.             case 15: v1 = v1 < v;    }
  1256.         o = lookup(operators); }
  1257.     while(operators[o]);
  1258.     if((o = *optr) && (o != ':') && (o != ')')) {
  1259.         script_error("Invalid operation");
  1260.         return 0; }
  1261.     return v1;
  1262. }
  1263.  
  1264. /*
  1265.  * Determine if a character is a space
  1266.  */
  1267. isspace(c)
  1268.     int c;
  1269. {
  1270.     return (c == ' ') || (c == '\t');
  1271. }
  1272.  
  1273. /*
  1274.  * Lookup in table entry in command strinf
  1275.  */
  1276. lookup(table)
  1277.     char **table;
  1278. {
  1279.     int i;
  1280.     char *ptr;
  1281.  
  1282.     skip_blanks();
  1283.     for(i=0; ptr = table[i]; ++i)
  1284.         if(strbeg(optr, ptr)) {
  1285.             optr += strlen(ptr);
  1286.             break; }
  1287.     skip_blanks();
  1288.     return i;
  1289. }
  1290.  
  1291. /*
  1292.  * Skip ahead past leading blanks
  1293.  */
  1294. skip_blanks()
  1295. {
  1296.     while(isspace(*optr))
  1297.         ++optr;
  1298.     return *optr;
  1299. }
  1300.  
  1301. /*
  1302.  * Expect a character in the input buffer
  1303.  */
  1304. expect(c)
  1305.     int c;
  1306. {
  1307.     if(skip_blanks() == c) {
  1308.         ++optr;
  1309.         return 0; }
  1310.     script_error("Syntax error");
  1311.     return -1;
  1312. }
  1313.  
  1314. /*
  1315.  * Test for the abort key and indicate if pressed
  1316.  */
  1317. testabort()
  1318. {
  1319.     if(wtstc() == 0x1B) {
  1320.         script_error("User abort");
  1321.         return -1; }
  1322.     return 0;
  1323. }
  1324.  
  1325. /*
  1326.  * Indicate an error occuring in a script file
  1327.  */
  1328. script_error(string)
  1329.     char *string;
  1330. {
  1331.     wprintf("** line %u: %s\n\r", line, string);
  1332.     abort_flag = -1;
  1333. }
  1334.  
  1335. /*
  1336.  * Parse a delimited string from (optr)
  1337.  */
  1338. parse_string(output)
  1339.     char *output;
  1340. {
  1341.     int d, c;
  1342.     if(d = skip_blanks()) {
  1343.         while(c = *++optr) {
  1344.             if(c == d) {
  1345.                 ++optr;
  1346.                 *output = 0;
  1347.                 skip_blanks();
  1348.                 return -1; }
  1349.             *output++ = c; } }
  1350.     script_error("Improper string");
  1351.     return 0;
  1352. }
  1353.  
  1354. /*
  1355.  * Parse string(OPTR) into 10 ARGC, ARGV parameters
  1356.  */
  1357. parse_args(outbuf)
  1358.     char *outbuf[];
  1359. {
  1360.     int i;
  1361.     char *ptr;
  1362.  
  1363.     i = 0;
  1364.     ptr = &outbuf[10];
  1365.     while(skip_blanks()) {
  1366.         outbuf[i++] = ptr;
  1367.         while(*optr && !isspace(*optr))
  1368.             *ptr++ = *optr++;
  1369.         *ptr++ = 0; }
  1370.  
  1371.     while(i < 10)
  1372.         outbuf[i++] = 0;
  1373. }
  1374.  
  1375. /*
  1376.  * Parse a filename from (optr)
  1377.  */
  1378. parse_filename(dest, suffix)
  1379.     char *dest, *suffix;
  1380. {
  1381.     int c, d;
  1382.     char *ptr;
  1383.  
  1384.     /* Test for direcrtory supplied */
  1385.     d = '\\';
  1386.     ptr = optr;
  1387.     while((c = *ptr++) && !isspace(c)) {
  1388.         if((c == '\\') || (c == ':'))
  1389.             d = 0; }
  1390.     /* If no directory, prepend home directory */
  1391.     if(d) {
  1392.         ptr = homedir;
  1393.         while(c = *ptr++)
  1394.             *dest++ = d = c;
  1395.         if(d != '\\')
  1396.             *dest++ = '\\'; }
  1397.     /* Copy in filename */
  1398.     d = -1;
  1399.     while((c = *optr) && !isspace(c)) {
  1400.         ++optr;
  1401.         if((*dest++ = c) == '.')
  1402.             d = 0; }
  1403.     /* Append suffix if requested */
  1404.     if(d && suffix) {
  1405.         while(c = *suffix++)
  1406.             *dest++ = c; }
  1407.     *dest = 0;
  1408.     return dest;
  1409. }
  1410.  
  1411. /*
  1412.  * Flush the capture buffer and optionally insert a string
  1413.  */
  1414. flush_capture(ptr)
  1415.     char *ptr;
  1416. {
  1417.     register unsigned i;
  1418.  
  1419.     for(cptr = i = 0; i < CAPTURE_SIZE; ++i)
  1420.         capture[i] = 0;
  1421.     if(ptr) {
  1422.         while(*ptr)
  1423.             capture[cptr++] = *ptr++; }
  1424. }
  1425.  
  1426. /*
  1427.  * Handle data received from the remote
  1428.  */
  1429. receive_data(c)
  1430.     char c;
  1431. {
  1432.     capture[cptr] = last_rx = c;
  1433.     if(++cptr >= CAPTURE_SIZE)
  1434.         cptr = 0;
  1435.  
  1436. /* echo char if selected */
  1437.     if(!invisible)
  1438.         wputc(c);
  1439.  
  1440. /* Write download file if selected */
  1441.     if(log_fp && ((c >= ' ') || (c == '\t') || (c == '\n')))
  1442.         putc(c, log_fp);
  1443. }
  1444.  
  1445. /*
  1446.  * Wait for string from remote
  1447.  */
  1448. wait_string(string, ticks)
  1449.     char *string;
  1450.     unsigned ticks;
  1451. {
  1452.     int c;
  1453.     unsigned j, s, os;
  1454.     char *ptr, *ptr1, *ptr2, buffer[50], flag;
  1455.  
  1456.     os = -1;
  1457.     flag = 0;
  1458.     ptr = buffer;
  1459.  
  1460.     do {
  1461.         if((c = Ctestc()) >= 0) {
  1462.             receive_data(*ptr++ = c);
  1463.             *ptr = 0; flag = -1; }
  1464.         else if(testabort())
  1465.             return 0;
  1466.         if(flag) {
  1467.             ptr1 = string;
  1468.             ptr2 = buffer;
  1469.             while(*ptr2 && (*ptr2 == *ptr1)) {
  1470.                 ++ptr1; ++ptr2; }
  1471.             if(*ptr2) {                /* strings do not match at all */
  1472.                 for(ptr1 = buffer; ptr1 < ptr; ++ptr1)
  1473.                     *ptr1 = *(ptr1+1);
  1474.                 --ptr; }
  1475.             else if(*ptr1)            /* Partial match, wait for more chars */
  1476.                 flag = 0;
  1477.             else                    /* Full match - we found it */
  1478.                 return -1 ; }
  1479.             get_time(&j, &j, &s);
  1480.             if(s != os) {
  1481.                 os = s;
  1482.                 --ticks; } }
  1483.     while(ticks);
  1484.     return 0;
  1485. }
  1486.  
  1487. /*
  1488.  * Search the capture buffer for a string
  1489.  */
  1490. search_buffer(string)
  1491.     char *string;
  1492. {
  1493.     char *ptr;
  1494.     unsigned sptr, rptr;
  1495.  
  1496.     sptr = cptr;
  1497.  
  1498.     do {
  1499.         rptr = sptr;
  1500.         ptr = string;
  1501.         while(*ptr && (*ptr == capture[rptr])) {
  1502.             ++ptr;
  1503.             if(++rptr >= CAPTURE_SIZE)
  1504.                 rptr = 0; }
  1505.  
  1506.         if(!*ptr)                    /* we found it */
  1507.             return 11;
  1508.         if(++sptr >= CAPTURE_SIZE)    /* advance scan pointer */
  1509.             sptr = 0; }
  1510.     while(sptr != cptr);
  1511.     return 0;
  1512. }
  1513.  
  1514. /*
  1515.  * Wait until no data is received
  1516.  */
  1517. wait_clear(ticks)
  1518.     unsigned ticks;
  1519. {
  1520.     int c, t;
  1521.     unsigned j, s, os;
  1522.  
  1523.     os = -1;
  1524.     t = ++ticks;
  1525.     do {
  1526.         if((c = Ctestc()) != -1) {
  1527.             receive_data(c);
  1528.             t = ticks; }
  1529.         else {
  1530.             if(testabort())
  1531.                 return;
  1532.             get_time(&j, &j, &s);
  1533.             if(s != os) {
  1534.                 os = s;
  1535.                 --t; } } }
  1536.     while(t);
  1537. }
  1538.